home *** CD-ROM | disk | FTP | other *** search
- #include "barrobj.h"
-
- #include <windows.h>
- #include "connect.h"
-
- CAsyncByteArray::CAsyncByteArray()
- {
- m_dwRefCount=0;
- m_punkInner=NULL;
- m_punkOuter=NULL;
-
- m_bTerminated=FALSE;
- m_bBlocking=TRUE;
-
- InitializeCriticalSection(&m_sectNewReadAllowed);
- m_nReadsPending=0;
- m_hevntNoReadsPending=NULL;
-
- m_hevntNewFillInfo=NULL;
- m_nFillAlloc=0;
- m_nFillInfo=0;
- m_pFillInfo=NULL;
- m_ulFillSize=0;
-
- InitializeCriticalSection(&m_sectLBConnect);
- m_pCacheArray=NULL;
- m_pDataArray=NULL;
- m_pLBConnect=NULL;
- }
-
- HRESULT CAsyncByteArray::Initialize(IUnknown* punkOuter) {
- try
- {
- m_punkInner=new CInnerUnk(this);
- }
- catch(...)
- {
- m_punkInner=NULL;
- return E_OUTOFMEMORY;
- }
-
- if (punkOuter)
- {
- m_punkOuter=punkOuter;
- }
- else
- {
- m_punkOuter=(IUnknown*) m_punkInner;
- }
-
- m_hevntNoReadsPending=CreateEvent(NULL, TRUE, TRUE, NULL);
- if (!m_hevntNoReadsPending)
- {
- return E_UNEXPECTED;
- }
- m_hevntNewFillInfo=CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!m_hevntNewFillInfo)
- {
- CloseHandle(m_hevntNoReadsPending);
- m_hevntNoReadsPending=NULL;
- return E_UNEXPECTED;
- }
- m_pFillInfo=(FILLINFO*) GlobalAlloc(GPTR, sizeof(FILLINFO)*FILLINFOINITSIZE);
- if (!m_pFillInfo)
- {
- CloseHandle(m_hevntNoReadsPending);
- m_hevntNoReadsPending=NULL;
- CloseHandle(m_hevntNewFillInfo);
- m_hevntNewFillInfo=NULL;
- return E_OUTOFMEMORY;
- }
- m_nFillAlloc=FILLINFOINITSIZE;
- m_nFillInfo=0;
- return S_OK;
- }
-
- CAsyncByteArray::~CAsyncByteArray()
- {
- if (m_pFillInfo)
- {
- WRITEFILLINFOLOCK;
- m_nFillInfo=0;
- m_nFillAlloc=0;
- GlobalFree((HGLOBAL)m_pFillInfo);
- m_pFillInfo=NULL;
- WRITEFILLINFOUNLOCK;
- }
-
- if (m_hevntNewFillInfo)
- {
- CloseHandle(m_hevntNewFillInfo);
- m_hevntNewFillInfo=NULL;
- }
-
- if (m_hevntNoReadsPending)
- {
- CloseHandle(m_hevntNoReadsPending);
- m_hevntNoReadsPending=NULL;
- }
- if (m_pCacheArray)
- {
- ILockBytes *pLB=m_pCacheArray;
- m_pCacheArray=NULL;
- pLB->Release();
- }
- if (m_pDataArray)
- {
- ILockBytes *pLB=m_pDataArray;
- m_pDataArray=NULL;
- pLB->Release();
- }
- if (m_pLBConnect)
- {
- CoDisconnectObject((IUnknown*) m_pLBConnect, NULL);
- if (m_pLBConnect)
- {
- delete m_pLBConnect;
- m_pLBConnect=NULL;
- }
- }
- DeleteCriticalSection(&m_sectLBConnect);
- DeleteCriticalSection(&m_sectNewReadAllowed);
- if (m_punkInner)
- {
- delete m_punkInner;
- }
- }
-
- HRESULT CAsyncByteArray::QueryInterface(REFIID riid, void** ppObject) {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- return m_punkOuter->QueryInterface(riid, ppObject);
- }
-
- ULONG CAsyncByteArray::AddRef()
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- return m_punkOuter->AddRef();
- }
-
- ULONG CAsyncByteArray::Release()
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- return m_punkOuter->Release();
- }
-
- CAsyncByteArray::CInnerUnk::CInnerUnk(CAsyncByteArray* pObj)
- {
- m_pObj=pObj;
- }
-
- HRESULT CAsyncByteArray::CInnerUnk::QueryInterface(REFIID riid, void** ppObject)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (riid==IID_IUnknown || riid==IID_ILockBytes)
- {
- *ppObject=(ILockBytes*) m_pObj;
- }
- else if (riid==IID_IFillLockBytes)
- {
- *ppObject=(IFillLockBytes*) m_pObj;
- }
- else if (riid==IID_IConnectionPointContainer)
- {
- *ppObject=(IConnectionPointContainer*) m_pObj;
- }
- else
- {
- return E_NOINTERFACE;
- }
- m_pObj->AddRef();
- return S_OK;
- }
-
- ULONG CAsyncByteArray::CInnerUnk::AddRef()
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- InterlockedIncrement((long*) &g_dwRefCount);
- InterlockedIncrement((long*) &m_pObj->m_dwRefCount);
- return m_pObj->m_dwRefCount;
- }
-
- ULONG CAsyncByteArray::CInnerUnk::Release()
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- ULONG dwRefCount=(m_pObj->m_dwRefCount)-1;
- InterlockedDecrement((long*) &g_dwRefCount);
- if (InterlockedDecrement((long*) &m_pObj->m_dwRefCount)==0)
- {
- delete m_pObj;
- return 0;
- }
- return dwRefCount;
- }
-
- HRESULT CAsyncByteArray::ReadAt(ULARGE_INTEGER ulOffset,void *pv, ULONG cb, ULONG *pcbRead)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
-
- if (pcbRead)
- {
- *pcbRead=0;
- }
- DWORD dwIndex=0;
- FILLINFO* pFillInfo=NULL;
- DWORDLONG ulEnd=ulOffset.QuadPart+cb;
- do
- {
- READFILLINFOLOCK;
- while (dwIndex<m_nFillInfo)
- {
- pFillInfo=m_pFillInfo+dwIndex;
- if (ulOffset.QuadPart>=pFillInfo->ulOffset)
- {
- if (ulEnd<=pFillInfo->ulOffset+pFillInfo->cb)
- {
- // All data is here
- READFILLINFOUNLOCK;
- return m_pCacheArray->ReadAt(ulOffset, pv, cb, pcbRead);
- }
- // Part of the data is here: try to read the rest from the Data Array
- DWORD cbAvailable=(DWORD) (pFillInfo->cb-(pFillInfo->ulOffset-ulOffset.QuadPart));
- ULARGE_INTEGER ulFirstNonAvailable;
- ulFirstNonAvailable.QuadPart=ulOffset.QuadPart+cbAvailable;
- // (cast DWORDLONG to DWORD is safe since cbAvailable<=cb per the preceding conditions)
- if (m_bBlocking)
- {
- if (m_pDataArray)
- {
- DWORD cbDataRead=0;
- m_pDataArray->ReadAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cb-cbAvailable, &cbDataRead);
- if (cbDataRead>0)
- {
- FillAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cbDataRead, NULL);
- if (cbDataRead==cb-cbAvailable)
- {
- cbDataRead=0;
- HRESULT hRes=m_pCacheArray->ReadAt(ulOffset, pv, cbAvailable, &cbDataRead);
- if (cbDataRead==cbAvailable)
- {
- if (pcbRead)
- {
- *pcbRead=cb;
- }
- return hRes;
- }
- }
- }
- }
- break; // for now we retry everything
- // This could be optimized by reading the available part now and obtain just the rest later
- }
- else
- {
- READFILLINFOUNLOCK;
- // Read from cache
- DWORD cbCacheRead=0;
- HRESULT hRes=m_pCacheArray->ReadAt(ulOffset, pv, cbAvailable, &cbCacheRead);
- if (pcbRead)
- {
- *pcbRead=cbCacheRead;
- }
- // Try to read the missing part from the Data Array
- if (cbCacheRead==cbAvailable && m_pDataArray)
- {
- DWORD cbDataRead=0;
- hRes=m_pDataArray->ReadAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cb-cbAvailable, &cbDataRead);
- if (cbDataRead>0)
- {
- if (pcbRead)
- {
- *pcbRead+=cbDataRead;
- }
- FillAt(ulFirstNonAvailable, ((BYTE*) pv)+cbAvailable, cbDataRead, NULL);
- }
- if (cbCacheRead+cbDataRead<cb)
- {
- hRes= ((m_bTerminated ||
- (m_ulFillSize && ulEnd>m_ulFillSize)) ? E_FAIL : ASTG_E_PENDING);
- }
- }
- return hRes;
- }
- }
- dwIndex++; // not this block
- };
- READFILLINFOUNLOCK;
- if (m_bBlocking)
- {
- if (m_ulFillSize && ulEnd>m_ulFillSize)
- {
- return E_FAIL;
- }
- DWORD res=WaitForSingleObject(m_hevntNewFillInfo, INFINITE); // wait until the next call to FillAt/FillAppend/FillSetSize/Terminate
- if (WAIT_FAILED==res)
- {
- return E_UNEXPECTED;
- }
- if (WAIT_ABANDONED==res)
- {
- return E_FAIL;
- }
- }
- else
- {
- if (pcbRead)
- {
- *pcbRead=0;
- }
- return (m_bTerminated ? E_FAIL : ASTG_E_PENDING);
- }
- }
- while (!m_bTerminated);
- return E_FAIL;
- }
-
- HRESULT CAsyncByteArray::WriteAt(ULARGE_INTEGER ulOffset,const void *pv, ULONG cb, ULONG *pcbWritten)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (m_pDataArray)
- {
- m_pDataArray->WriteAt(ulOffset, pv, cb, pcbWritten);
- }
-
- return FillAt(ulOffset, pv, cb, pcbWritten);
- }
-
- HRESULT CAsyncByteArray::Flush( void)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (m_pDataArray)
- {
- m_pDataArray->Flush();
- }
- if (m_pCacheArray)
- {
- return m_pCacheArray->Flush();
- }
- return S_OK;
- }
-
- HRESULT CAsyncByteArray::SetSize(ULARGE_INTEGER cb)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (m_pDataArray)
- {
- m_pDataArray->SetSize(cb);
- }
- return SetFillSize(cb);
- }
-
- HRESULT CAsyncByteArray::LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
-
- if (m_pDataArray)
- {
- m_pDataArray->LockRegion(libOffset, cb, dwLockType);
- }
-
- return m_pCacheArray->LockRegion(libOffset, cb, dwLockType);
- }
-
- HRESULT CAsyncByteArray::UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
-
- if (m_pDataArray)
- {
- m_pDataArray->UnlockRegion(libOffset, cb, dwLockType);
- }
-
- return m_pCacheArray->UnlockRegion(libOffset, cb, dwLockType);
- }
-
- HRESULT CAsyncByteArray::Stat(STATSTG *pstatstg, DWORD grfStatFlag) {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
-
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
- return m_pCacheArray->Stat(pstatstg, grfStatFlag);
- }
-
-
- // IFillLockBytes methods
- HRESULT CAsyncByteArray::SetFillSize(ULARGE_INTEGER cb) {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
- HRESULT hRes=m_pCacheArray->SetSize(cb);
- if (FAILED(hRes))
- {
- return hRes;
- }
- WRITEFILLINFOLOCK;
- m_ulFillSize=cb.QuadPart;
- DWORD dwIndex=0;
- FILLINFO* pFillInfo=NULL;
- while (dwIndex<m_nFillInfo)
- {
- pFillInfo=m_pFillInfo+dwIndex;
- // is this block outside the new size?
- if (pFillInfo->ulOffset>=cb.QuadPart)
- {
- m_nFillInfo=dwIndex; // invalidate it and all the following!
- break;
- }
- // is part of this block outsize the new size?
- if (pFillInfo->ulOffset+pFillInfo->cb>cb.QuadPart)
- {
- pFillInfo->cb=cb.QuadPart-pFillInfo->ulOffset; // truncate it
- m_nFillInfo=dwIndex+1; // remove all the following blocks
- break;
- }
- dwIndex++;
- }
- WRITEFILLINFOUNLOCK;
- PulseEvent(m_hevntNewFillInfo);
- return hRes;
- }
-
- HRESULT CAsyncByteArray::FillAppend(void const *pv, ULONG cb, ULONG *pcbWritten)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
-
- WRITEFILLINFOLOCK; // for now: suboptimal since it disables reading while appending!
- DWORDLONG ulEnd;
- FILLINFO* pFillInfo=NULL;
- if (m_nFillInfo>0)
- {
- pFillInfo=m_pFillInfo+(m_nFillInfo-1);
- ulEnd=pFillInfo->ulOffset+pFillInfo->cb;
- }
- else
- {
- ulEnd=0;
- }
- ULONG cbWritten=0;
- HRESULT hRes=m_pCacheArray->WriteAt(*((ULARGE_INTEGER*) &ulEnd), pv, cb, &cbWritten);
- if (cbWritten>0 && m_nFillInfo==0)
- {
- m_pFillInfo->cb=cbWritten;
- m_pFillInfo->ulOffset=ulEnd;
- m_nFillInfo=1;
- pFillInfo=m_pFillInfo;
- }
- else
- {
- pFillInfo->cb+=cbWritten;
- }
- if (pcbWritten)
- {
- *pcbWritten=cbWritten;
- }
- if (m_ulFillSize && ulEnd>m_ulFillSize)
- {
- m_ulFillSize=ulEnd;
- }
- WRITEFILLINFOUNLOCK;
- PulseEvent(m_hevntNewFillInfo);
- return hRes;
- }
-
- HRESULT CAsyncByteArray::FillAt(ULARGE_INTEGER ulOffset, void const *pv, ULONG cb, ULONG *pcbWritten)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (!m_pCacheArray)
- {
- return ASTG_E_NOTINITIALIZED;
- }
- ULONG cbWritten=0;
- HRESULT hRes=m_pCacheArray->WriteAt(ulOffset, pv, cb, &cbWritten);
- if (pcbWritten)
- {
- *pcbWritten=cbWritten;
- }
-
- DWORD dwIndex=0;
- DWORDLONG ulEnd=ulOffset.QuadPart+cbWritten;
- BOOL bExtended=FALSE;
- FILLINFO* pFillInfo=NULL;
- WRITEFILLINFOLOCK;
- if (m_ulFillSize && ulEnd>m_ulFillSize)
- {
- m_ulFillSize=ulEnd;
- }
- while (dwIndex<m_nFillInfo)
- {
- pFillInfo=m_pFillInfo+dwIndex;
- // 1.- New block is completely before this block: insert new FillInfo
- if (ulEnd<pFillInfo->ulOffset)
- {
- pFillInfo=NULL;
- if (m_nFillInfo>=m_nFillAlloc)
- {
- DWORD nNewFillAlloc=m_nFillAlloc+FILLINFOREALLOCSIZE;
- FILLINFO* pTemp=(FILLINFO*) GlobalReAlloc(m_pFillInfo, sizeof(FILLINFO)*nNewFillAlloc, GMEM_ZEROINIT);
- if (pTemp)
- {
- m_pFillInfo=pTemp;
- m_nFillInfo=nNewFillAlloc;
- }
- else
- {
- WRITEFILLINFOUNLOCK;
- return E_OUTOFMEMORY;
- }
- }
- pFillInfo=m_pFillInfo+dwIndex;
- memmove((pFillInfo+1), pFillInfo, sizeof(FILLINFO)*(m_nFillInfo-dwIndex));
- pFillInfo->ulOffset=ulOffset.QuadPart;
- pFillInfo->cb=cbWritten;
- m_nFillInfo++;
- break;
- }
- // 2.- New block starts before or with this block:
- // change ulOffset/cb and check for merge with following block(s)
- if (ulOffset.QuadPart<=pFillInfo->ulOffset)
- {
- pFillInfo->ulOffset=ulOffset.QuadPart;
- if (ulEnd>pFillInfo->ulOffset+pFillInfo->cb)
- {
- // this block became longer
- pFillInfo->cb=ulEnd-pFillInfo->ulOffset;
- bExtended=TRUE; // need to check for possible merge wih following block(s)
- }
- else {
- // did not change end of this block: done.
- break;
- }
- }
- // 3.- new block starts within this block
- // change cb and check for merge with following block(s)
- else if (ulOffset.QuadPart<=pFillInfo->ulOffset+pFillInfo->cb)
- {
- if (ulEnd>pFillInfo->ulOffset+pFillInfo->cb)
- {
- // this block became longer
- pFillInfo->cb=ulEnd-pFillInfo->ulOffset;
- bExtended=TRUE; // need to check for possible merge with following block(s)
- }
- else
- {
- // did not change end of this block: done.
- break;
- }
- }
- if (bExtended)
- {
- // if the block was extended, check if can be merged with the following block(s)
- DWORD dwIndex1=dwIndex+1;
- DWORD dwRemoveCount=0; // will remove merge block(s)
- while (dwIndex1<m_nFillInfo)
- {
- if (ulEnd<m_pFillInfo[dwIndex1].ulOffset)
- {
- // new block ends before this block: no more merges
- break;
- }
- else
- {
- // merge this block with first modified block
- dwRemoveCount++; // flag it for removal
- if (m_pFillInfo[dwIndex1].ulOffset+m_pFillInfo[dwIndex1].cb>ulEnd)
- {
- // this block was bigger than the newly written one:
- // adjust first modified block
- pFillInfo->cb=m_pFillInfo[dwIndex1].ulOffset+m_pFillInfo[dwIndex1].cb-pFillInfo->ulOffset;
- // no more merges since this block did not grow
- break;
- }
- }
- dwIndex1++;
- }
- if (dwRemoveCount)
- {
- // remove merged blocks
- memmove((pFillInfo+1), m_pFillInfo+dwIndex+1+dwRemoveCount, sizeof(FILLINFO)*(m_nFillInfo-dwRemoveCount-dwIndex-1));
- m_nFillInfo-=dwRemoveCount;
- }
- break;
- }
- dwIndex++;
- }
- if (dwIndex>=m_nFillInfo)
- {
- // new block did not affect any of the existing blocks: append
- pFillInfo=NULL;
- if (m_nFillInfo>=m_nFillAlloc)
- {
- DWORD nNewFillAlloc=m_nFillAlloc+FILLINFOREALLOCSIZE;
- FILLINFO* pTemp=(FILLINFO*) GlobalReAlloc(m_pFillInfo, sizeof(FILLINFO)*nNewFillAlloc, GMEM_ZEROINIT);
- if (pTemp)
- {
- m_pFillInfo=pTemp;
- m_nFillInfo=nNewFillAlloc;
- }
- else
- {
- WRITEFILLINFOUNLOCK;
- return E_OUTOFMEMORY;
- }
- }
- pFillInfo=m_pFillInfo+dwIndex;
- pFillInfo->ulOffset=ulOffset.QuadPart;
- pFillInfo->cb=cbWritten;
- m_nFillInfo++;
- }
- WRITEFILLINFOUNLOCK;
- PulseEvent(m_hevntNewFillInfo);
- return hRes;
- }
-
- HRESULT CAsyncByteArray::Terminate(DWORD dwStatus)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- m_bTerminated=TRUE;
- PulseEvent(m_hevntNewFillInfo);
- return S_OK;
- }
-
- // IConnectionPointContainer methods
- HRESULT CAsyncByteArray::EnumConnectionPoints(LPENUMCONNECTIONPOINTS FAR* ppEnum)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- //ASSERT(FALSE);
- return E_NOTIMPL;
- }
-
- HRESULT CAsyncByteArray::FindConnectionPoint(REFIID iid, LPCONNECTIONPOINT FAR* ppCP)
- {
- if (IsBadWritePtr(this, sizeof(*this)))
- {
- return E_POINTER;
- }
- if (IsBadWritePtr(ppCP, sizeof(*ppCP)))
- {
- return E_POINTER;
- }
- if (iid==IID_ILockBytes)
- {
- if (!m_pLBConnect)
- {
- try
- {
- m_pLBConnect=new CLockBytesConnectionPoint(this);
- }
- catch(...)
- {
- m_pLBConnect=NULL;
- }
- }
- if (!m_pLBConnect)
- {
- return E_OUTOFMEMORY;
- }
- if (FAILED(m_pLBConnect->QueryInterface(IID_IConnectionPoint, (void**) ppCP)))
- {
- //ASSERT(FALSE);
- return E_UNEXPECTED;
- }
- }
- /*
- else if (iid==IID_IFillLockBytes)
- {
- if (!m_pFillLBConnect)
- {
- try
- {
- m_pFillLBConnect=new CFillLockBytesConnectionPoint(this);
- }
- catch(...)
- {
- m_pFillLBConnect=NULL;
- }
- }
- if (!m_pFillLBConnect)
- {
- return E_OUTOFMEMORY;
- }
- if (FAILED(m_pFillLBConnect->QueryInterface(IID_IConnectionPoint, *ppCP)))
- {
- ASSERT(FALSE);
- return E_UNEXPECTED;
- }
- }
- else if (iid==IID_IBindStatusCallBack)
- {
- if (!m_pBSCConnect)
- {
- try
- {
- m_pBSCConnect=new CBSCConnectionPoint(this);
- }
- catch(...)
- {
- m_pBSCConnect=NULL;
- }
- }
- if (!m_pBSCConnect)
- {
- return E_OUTOFMEMORY;
- }
- if (FAILED(m_pBSCConnect->QueryInterface(IID_IConnectionPoint, *ppCP)))
- {
- ASSERT(FALSE);
- return E_UNEXPECTED;
- }
- }
- */
- else
- {
- return CONNECT_E_NOCONNECTION;
- }
- return S_OK;
- }
-